﻿using FreeSql;
using FreeSql.Aop;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.DependencyInjection.Extensions;
using Singer.Core;
using Singer.Shared;
using Singer.Shared.UserContext;

namespace Singer.Middleware.FreeSql;

/// <summary>
/// FreeSql 服务拓展
/// </summary>
public static class FreeSqlServiceExtensions
{
    /// <summary>
    /// FreeSql过滤器名 - 软删除
    /// </summary>
    const string FILTER_NAME_SOFT_DELETE = "SoftDelete";

    public static void AddFreeSql(this IServiceCollection services, IConfiguration configuration, Action<FreeSqlBuilder>? builderAction = null)
    {
        FreeSqlOptions? options = configuration.GetSection(FreeSqlOptions.ConfigKey).Get<FreeSqlOptions>();
        if (options == null)
            throw new Exception("【FreeSql】Config was not found.");
        options.Validate();
        FreeSqlBuilder freeSqlBuilder = new FreeSqlBuilder()
            .UseConnectionString(options.DataType, options.ConnectionString)
            .UseAutoSyncStructure(options.AutoSyncStructure)//自动同步表结构。开发环境很快乐，生产环境千万别用！
            .UseMonitorCommand(x => Console.WriteLine("【FreeSql】：" + x.CommandText));
        builderAction?.Invoke(freeSqlBuilder);
        IFreeSql freeSql = freeSqlBuilder.Build();
        freeSql.UseJsonMap();
        //全局过滤器，过滤掉软删除的数据
        freeSql.GlobalFilter.ApplyOnly<ISoftDelete>(FILTER_NAME_SOFT_DELETE, x => x.IsDeleted == false);
        services.TryAddSingleton<IFreeSql>(sp =>
        {
            IUserContextAccessor? userContextAccessor = sp.GetService<IUserContextAccessor>();
            if (options.UseAopAudit)
                freeSql.Aop.AuditValue += (sender, e) => Aop_AuditValue(sender, e, userContextAccessor);//Aop新增编辑触发事件
            return freeSql;
        });
    }

    /// <summary>
    /// 继承了ICreator的实体在新增数据时自动加上创建人信息
    /// 继承了IChanger的实体在修改数据时自动加上修改人信息 （必须先查再修改，内存中有实体信息的才可以）
    /// </summary>
    private static void Aop_AuditValue(object? sender, AuditValueEventArgs e, IUserContextAccessor? userContextAccessor)
    {
        e.ObjectAuditBreak = true;
        IUserContext? _userContext = userContextAccessor?.UserContext;
        if (e.AuditValueType == AuditValueType.Insert)
        {
            if (e.Object is ICreator creator)
            {
                if (string.IsNullOrWhiteSpace(creator.CreatorId) && !string.IsNullOrWhiteSpace(_userContext?.UserId))
                {
                    e.Object.GetType().GetProperty(nameof(creator.CreatorId))?.SetValue(e.Object, _userContext.UserId);
                    e.Object.GetType().GetProperty(nameof(creator.CreatorName))?.SetValue(e.Object, _userContext.UserName);
                }
                if (creator.CreateTime == DateTime.MinValue)
                    e.Object.GetType().GetProperty(nameof(creator.CreateTime))?.SetValue(e.Object, Cores.BeiJingNow);
            }
        }
        else if (e.AuditValueType == AuditValueType.Update)
        {
            if (e.Object is IChanger changer)
            {
                if (!(e.Object is ISoftDelete softDelete && softDelete.IsDeleted))
                {
                    if (!string.IsNullOrWhiteSpace(_userContext?.UserId))
                    {
                        e.Object.GetType().GetProperty(nameof(changer.ChangerId))?.SetValue(e.Object, _userContext.UserId);
                        e.Object.GetType().GetProperty(nameof(changer.ChangerName))?.SetValue(e.Object, _userContext.UserName);
                    }
                    e.Object.GetType().GetProperty(nameof(changer.ChangeTime))?.SetValue(e.Object, Cores.BeiJingNow);
                }
            }
        }
    }
}
